home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 4 / ETO Development Tools 4.iso / Tools - Objects / MacApp / MacApp 2.0.1 / Experimental enhancements / MacApp Sizers / USizerView.impl.p < prev    next >
Text File  |  1990-11-08  |  52KB  |  1,975 lines

  1. {$S AInit}
  2.  
  3. PROCEDURE InitUSizerView;
  4.  
  5.     BEGIN
  6.     SetVRect(gVertSBarSetback, 0, 0, kSBarSizeMinus1, 0);
  7.     SetVRect(gHorzSBarSetback, 0, 0, 0, kSBarSizeMinus1);
  8.     SetVRect(gBothSBarSetback, 0, 0, kSBarSizeMinus1, kSBarSizeMinus1);
  9.  
  10.     gNonPanes := NewIntegerArray(2);
  11.     gNonPanes.AddElement(GetClassIDFromName('TSScrollBar'));
  12.     gNonPanes.AddElement(GetClassIDFromName('TSplitter'));
  13.  
  14.     RegisterStdType('TSplitter', kStdSplitter);
  15.  
  16.     IF gDeadStripSuppression THEN BEGIN
  17.         IF Member(TObject(NIL), TSizerView) THEN;
  18.         IF Member(TObject(NIL), THorizontalSizer) THEN;
  19.         IF Member(TObject(NIL), TVerticalSizer) THEN;
  20.         IF Member(TObject(NIL), TSplitter) THEN;
  21.         END;
  22.     END;
  23.  
  24. PROCEDURE ExcludeAsPane(obj: TObject);
  25. { Make the class of obj ineligible for pane-dom }
  26.  
  27.     VAR
  28.         itsClassId:        ObjClassId;
  29.  
  30.     BEGIN
  31.     IF obj <> NIL THEN BEGIN
  32.         itsClassId := GetClassID(obj);
  33.         gNonPanes.AddUnique(itsClassId);
  34.         END;
  35.     END;
  36.  
  37. {$S ADoCommand}
  38. FUNCTION CloneAView(aView: TView): TView;
  39. { Clone aView and all its subviews }
  40.  
  41.     VAR
  42.         newView:        TView;
  43.  
  44.     PROCEDURE CloneASubview(aSubView: TView);
  45.         VAR    newSubview:        TView;
  46.         BEGIN
  47.         newSubView := CloneAView(aSubView);
  48.         newView.AddSubView(newSubView);
  49.         END;
  50.  
  51.     PROCEDURE CreateIfScrollBar(aScroller: TScroller; dir: VHSelect);
  52.  
  53.         BEGIN
  54.         IF aScroller.fScrollBars[dir] <> NIL THEN BEGIN    { create the dir scroll bar }
  55.             aScroller.fScrollBars[dir] := NIL;
  56.             aScroller.CreateScrollBar(dir);
  57.             END;
  58.         END;
  59.  
  60.     BEGIN
  61.     newView := TView(aView.Clone);
  62.     newView.fNextHandler := NIL;                { will be set by AddSubView }
  63.     IF aView.fSubViews <> NIL THEN BEGIN
  64.         newView.fSubViews := NewList;
  65.         aView.EachSubView(CloneASubview);
  66.         END;
  67.     IF Member(aView, TScroller) THEN BEGIN        { aView is a TScroller }
  68.         CreateIfScrollBar(TScroller(newView), h);
  69.         CreateIfScrollBar(TScroller(newView), v);
  70.         END;
  71.     CloneAView := newView;
  72.     END;
  73.  
  74. {$S ARes}
  75. FUNCTION OtherDirection(direction: VHSelect): VHSelect;
  76.  
  77.     BEGIN
  78.     IF direction = v
  79.         THEN OtherDirection := h
  80.         ELSE OtherDirection := v;
  81.     END;
  82.  
  83. {-------------------------- TVRectList ----------------------}
  84.  
  85. {$S AOpen}
  86.  
  87. PROCEDURE TVRectList.IVRectList(initialSize: INTEGER);
  88.  
  89.     BEGIN
  90.     IDynamicArray(initialSize, SIZEOF(VRect));
  91.     END;
  92.  
  93. {$S ARes}
  94.  
  95. FUNCTION TVRectList.At(index: ArrayIndex): VRect;
  96. { Code stolen from TList.At }
  97.  
  98.     BEGIN
  99.     IF qRangeCheck & ((index <= kEmptyIndex) | (index > fSize)) THEN BEGIN
  100.         WRITELN('fSize = ', fSize: 1, '  index = ', index: 1);
  101.         ProgramBreak('Range Check in TVRectList.At');
  102.         END;
  103.  
  104.     At := VRectPtr(ComputeAddress(index))^;
  105.     END;
  106.  
  107. PROCEDURE TVRectList.AtPut(index: ArrayIndex; newItem: VRect);
  108. { Code stolen from TList.AtPut }
  109.  
  110.     BEGIN
  111.     WHILE index > fSize DO            { add items to list so index is valid }
  112.         InsertElementsBefore(fSize + 1, @gZeroVRect, 1);
  113.  
  114.     VRectPtr(ComputeAddress(index))^ := newItem;
  115.     END;
  116.  
  117. PROCEDURE TVrectList.AtCoordPut(index: ArrayIndex; whichCoord: Coordinate;
  118.                                 newCoord: VCoordinate);
  119. { Change a single coordinate of the specified VRect to the given value. }
  120.  
  121.     VAR
  122.         pVR:        VRectPtr;
  123.  
  124.     BEGIN
  125.     IF qRangeCheck & ((index <= kEmptyIndex) | (index > fSize)) THEN BEGIN
  126.         WRITELN('fSize = ', fSize: 1, '  index = ', index: 1);
  127.         ProgramBreak('Range Check in TVRectList.AtCoordPut');
  128.         END;
  129.  
  130.     pVR := VRectPtr(ComputeAddress(index));
  131.     CASE whichCoord OF
  132.         kLeftCoord:        pVR^.left := newCoord;
  133.         kRightCoord:    pVR^.right := newCoord;
  134.         kTopCoord:        pVR^.top := newCoord;
  135.         kBottomCoord:    pVR^.bottom := newCoord;
  136.         END;
  137.     END;
  138.  
  139. {$S ANever}
  140.  
  141. PROCEDURE TVrectList.AtSetVRect(index: ArrayIndex; left, top, right, bottom: VCoordinate);
  142. { Change the specified VRect’s coordinates to the given values. }
  143.  
  144.     VAR
  145.         pVR:        VRectPtr;
  146.  
  147.     BEGIN
  148.     IF qRangeCheck & ((index <= kEmptyIndex) | (index > fSize)) THEN BEGIN
  149.         WRITELN('fSize = ', fSize: 1, '  index = ', index: 1);
  150.         ProgramBreak('Range Check in TVRectList.AtSetVRect');
  151.         END;
  152.  
  153.     pVR := VRectPtr(ComputeAddress(index));
  154.     SetVRect(pVR^, left, top, right, bottom);
  155.     END;
  156.  
  157. {$S APane}
  158.  
  159. PROCEDURE TVRectList.InsertBefore(index: ArrayIndex; item: VRect);
  160.  
  161.     BEGIN
  162.     IF qRangeCheck & ((index <= kEmptyIndex) | (index > fSize + 1)) THEN
  163.         BEGIN
  164.         WRITELN('fSize = ', fSize: 1, '  index = ', index: 1);
  165.         ProgramBreak('Range Check in TVRectList.InsertBefore');
  166.         END;
  167.  
  168.     InsertElementsBefore(index, @item, 1);
  169.     END;
  170.  
  171. {$S AFields}
  172.  
  173. PROCEDURE TVRectList.Fields(PROCEDURE DoToField(fieldName: Str255;
  174.                                                 fieldAddr: Ptr;
  175.                                                 fieldType: INTEGER)); OVERRIDE;
  176.  
  177.     BEGIN
  178.     DoToField('TVRectList', NIL, bClass);
  179.     INHERITED Fields(DoToField);
  180.     END;
  181.  
  182. PROCEDURE TVRectList.DynamicFields(PROCEDURE DoToField(fieldName: Str255;
  183.                                                        fieldAddr: Ptr;
  184.                                                        fieldType: integer)); OVERRIDE;
  185.  
  186.     FUNCTION DoToElement(theIndex: ArrayIndex): Boolean;
  187.  
  188.         VAR
  189.             aString:            Str255;
  190.  
  191.         BEGIN
  192.         DoToElement := FALSE;
  193.         NumToString(theIndex, aString);
  194.         aString := CONCAT('[', aString, ']');
  195.         DoToField(aString, ComputeAddress(theIndex), bVRect);
  196.         END;
  197.  
  198.     BEGIN
  199.     DoToField('VRect Elements', NIL, bTitle);
  200.  
  201.     IF EachElementDoTil(DoToElement, kIterateForward) <> kEmptyIndex THEN;
  202.     END;
  203.  
  204. {-------------------------- TSizerView ----------------------}
  205.  
  206. {$S AOpen}
  207.  
  208. PROCEDURE TSizerView.Initialize; OVERRIDE;
  209.  
  210.     BEGIN
  211.     fPanes := NIL;
  212.     fSetbacks := NIL;
  213.     fSizerRects := NIL;
  214.     fSplitter := NIL;
  215.     fMinPaneSize := kMinSizerPane;
  216.     fSizerThickness := kSizerThickness;
  217.     END;
  218.  
  219. PROCEDURE TSizerView.IRes(itsDocument: TDocument; itsSuperView: TView; VAR itsParams: Ptr); OVERRIDE;
  220.  
  221.     BEGIN
  222.     IObject;                        (* shouldn’t this be called automagically? *)
  223.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  224.     InitLists;
  225.     END;
  226.  
  227. PROCEDURE TSizerView.ISizerView(itsDocument: TDocument;
  228.                                 itsSuperview: TView;
  229.                                 itsLocation: VPoint;
  230.                                 itsSize: VPoint;
  231.                                 itsHSizeDet, itsVSizeDet: SizeDeterminer);
  232.  
  233.     BEGIN
  234.     IObject;                        (* shouldn’t this be called automagically? *)
  235.     IView(itsDocument, itsSuperview, itsLocation, itsSize, itsHSizeDet, itsVSizeDet);
  236.     InitLists;
  237.     END;
  238.  
  239. PROCEDURE TSizerView.InitLists;
  240. { Create and initialize the various lists of subviews and VRects }
  241.  
  242.     VAR
  243.         aVRectList:        TVRectList;
  244.  
  245.     BEGIN
  246.     { Create a list for the subviews }
  247.     fPanes := NewList;
  248.     IF qDebug THEN fPanes.SetEltType('TView');
  249.  
  250.     { Initialize list of setback VRects }
  251.     NEW(aVRectList);
  252.     FailNIL(aVRectList);
  253.     aVRectList.IVRectList(2);        { big enough for two subpanes }
  254.     fSetbacks := aVRectList;
  255.  
  256.     { Initialize list of sizer VRects }
  257.     NEW(aVRectList);
  258.     FailNIL(aVRectList);
  259.     aVRectList.IVRectList(1);        { big enough for one sizer rectangle }
  260.     fSizerRects := aVRectList;
  261.     END;
  262.  
  263. {$S AOpen}
  264.  
  265. PROCEDURE TSizerView.FixupPanes(equalSpacing: BOOLEAN);
  266. { a/k/a “PostRes”; call after IRes (NewTemplateWindow).
  267.   If equalSpacing is TRUE, make the panes of equal size;
  268.   if equalSpacing is FALSE, try to locate the panes using their fSizes. }
  269.  
  270.     VAR
  271.         panes:                INTEGER;
  272.         sizers:                INTEGER;
  273.         i:                    INTEGER;
  274.         thePane:            TView;
  275.         aScroller:            TScroller;
  276.         aVRect:                VRect;
  277.         defaultSizerRects:    TVRectList;
  278.  
  279.     PROCEDURE GatherPanes(thePane: TView);
  280.     { Figure out which subviews are panes: all but those whose class id
  281.       is in the gNonPanes list. }
  282.  
  283.         BEGIN
  284.         IF NOT gNonPanes.Contains(GetClassId(thePane)) THEN
  285.             fPanes.InsertLast(thePane);
  286.         END;
  287.  
  288.     PROCEDURE InitSetbacks(thePane: TView);
  289.     { Initialize the setbacks according to whether each pane has scroll bars or not. }
  290.  
  291.         BEGIN
  292.         aVRect := gZeroVRect;            { assume subview fills pane }
  293.         IF Member(thePane, TScroller) THEN
  294.             BEGIN                        { subview is a scroller--check for scroll bars }
  295.             aScroller := TScroller(thePane);
  296.             IF aScroller.fScrollBars[v] <> NIL THEN
  297.                 IF aScroller.fScrollBars[h] <> NIL THEN
  298.                     aVRect := gBothSBarSetback
  299.                 ELSE
  300.                     aVRect := gVertSBarSetback
  301.             ELSE
  302.                 IF aScroller.fScrollBars[h] <> NIL THEN
  303.                     aVRect := gHorzSBarSetback;
  304.             END;
  305.         fSetbacks.AtPut(i, aVRect);
  306.         i := i + 1;
  307.         END;
  308.  
  309.     FUNCTION PaneCompare(item1, item2: TObject): CompareResult;
  310.  
  311.         BEGIN
  312.         { Pane comparison is direction dependent! }
  313.         PaneCompare := SELF.CompareViewLocations(TView(item1), TView(item2));
  314.         END;
  315.  
  316.     BEGIN                                { TSizerView.FixupPanes }
  317.     EachSubView(GatherPanes);            { make a list of the panes }
  318.     panes := fPanes.GetSize;
  319.     IF qDebug & (panes = 0) THEN
  320.         ProgramBreak('No panes, no gains!');
  321.     fPanes.SortBy(PaneCompare);            { order panes by location }
  322.  
  323.     i := 1;
  324.     fPanes.Each(InitSetbacks);            { initialize setback VRects }
  325.     sizers := panes - 1;                { number of sizers needed }
  326.  
  327.     { Create a list of sizer rectangles }
  328.     NEW(defaultSizerRects);
  329.     FailNIL(defaultSizerRects);
  330.     defaultSizerRects.IVRectList(sizers);
  331.  
  332.     IF equalSpacing THEN BEGIN            { Initialize the sizer rectangles… }
  333.         FOR i := 1 TO sizers DO BEGIN    { …to be evenly spaced }
  334.             aVRect := GetDefaultSizerRect(i);    { direction dependent! }
  335.             defaultSizerRects.AtPut(i, aVRect);
  336.             END;
  337.         END
  338.     ELSE BEGIN                            { Initialize the sizer rectangles… }
  339.         FOR i := 1 TO sizers DO BEGIN    { …from the panes’ locations and sizes }
  340.             thePane := TView(fPanes.At(i));
  341.             aVRect := GetNextSizerRect(thePane);
  342.             defaultSizerRects.AtPut(i, aVRect);
  343.             (* make another pass to check the sizer rects for consistency *)
  344.             END;
  345.         END;
  346.  
  347.     IF sizers > 0 THEN                    { Fit the subviews into the sizer rects }
  348.         SetPanes(defaultSizerRects, kDontInvalidate);
  349.     defaultSizerRects.Free;
  350.     END;
  351.  
  352. {$S AClose}
  353.  
  354. PROCEDURE TSizerView.Free; OVERRIDE;
  355.  
  356.     BEGIN
  357.     FreeIfObject(fSetbacks);
  358.     fSetbacks := NIL;
  359.     FreeIfObject(fSizerRects);
  360.     fSizerRects := NIL;
  361.  
  362.     INHERITED Free;
  363.     END;
  364.  
  365. {$S APane}
  366.  
  367. PROCEDURE TSizerView.AddPane(newPane: TView; itsLocation: VCoordinate; itsSetbacks: VRect);
  368. { Install thePane at the specified location, shrinking any existing pane accordingly. }
  369.  
  370.     VAR
  371.         itsPosition:    INTEGER;
  372.         itsSizerRect:    VRect;
  373.         newSizerRects:    TVRectList;
  374.  
  375.     BEGIN
  376.     IF (fSubViews = NIL) | (fSubViews.GetSameItemNo(newPane) = 0) THEN
  377.         AddSubView(newPane);
  378.     newSizerRects := NIL;
  379.  
  380.     IF GetNumberOfPanes = 0 THEN
  381.         itsPosition := 0
  382.     ELSE BEGIN        { need to add a sizer rect }
  383.         itsPosition := FindSizerPosition(itsLocation);
  384.         newSizerRects := TVRectList(fSizerRects.Clone);
  385.         END;
  386.  
  387.     { Add the new pane to the list }
  388.     fPanes.InsertBefore(itsPosition+1, newPane);
  389.  
  390.     { Add the new pane’s setbacks to the list }
  391.     fSetbacks.InsertBefore(itsPosition+1, itsSetbacks);
  392.  
  393.     IF newSizerRects <> NIL THEN BEGIN    { add the new sizer rect and resize panes }
  394.         itsSizerRect := MakeSizerRect(itsLocation);
  395.         newSizerRects.InsertBefore(itsPosition, itsSizerRect);
  396.         SetPanes(newSizerRects, kDontInvalidate);
  397.         newSizerRects.Free;                { discard temp sizerRects object }
  398.         END;
  399.     END;
  400.  
  401. PROCEDURE TSizerView.AddEqualPane(newPane: TView; itsPosition: INTEGER; itsSetbacks: VRect);
  402. { Install thePane at the specified position, resizing all panes equally. }
  403.  
  404.     VAR
  405.         existingPanes:    INTEGER;
  406.         itsSizerRect:    VRect;
  407.         newSizerRects:    TVRectList;
  408.         s:                INTEGER;
  409.  
  410.     BEGIN
  411.     IF (fSubViews = NIL) | (fSubViews.GetSameItemNo(newPane) = 0) THEN
  412.         AddSubView(newPane);
  413.  
  414.     existingPanes := fPanes.GetSize;
  415.     { constrain value of itsPosition to [1..existingPanes+1] }
  416.     IF itsPosition <= 0 THEN
  417.         itsPosition := 1
  418.     ELSE IF itsPosition > existingPanes+1 THEN
  419.         itsPosition := existingPanes + 1;
  420.     fPanes.InsertBefore(itsPosition, newPane);
  421.  
  422.     { Add the new pane’s setbacks to the list }
  423.     fSetbacks.InsertBefore(itsPosition, itsSetbacks);
  424.  
  425.     IF existingPanes > 0 THEN BEGIN        { need to add a sizer rect too }
  426.         newSizerRects := TVRectList(fSizerRects.Clone);
  427.         newSizerRects.AtPut(newSizerRects.GetSize+1, gZeroVRect);    { append a rect }
  428.         FOR s := 1 TO newSizerRects.GetSize DO BEGIN    { resize each rect }
  429.             itsSizerRect := GetDefaultSizerRect(s);
  430.             newSizerRects.AtPut(s, itsSizerRect);
  431.             END;
  432.         SetPanes(newSizerRects, kDontInvalidate);    { resize the panes to fit }
  433.         newSizerRects.Free;                { discard temp sizerRects object }
  434.         END;
  435.     END;
  436.  
  437. FUNCTION TSizerView.DeletePane(whichPane, whichSizer: INTEGER): TView;
  438.  
  439.     VAR
  440.         thePane:        TView;
  441.         changedPane:    TView;
  442.         scroller:        TScroller;
  443.         newSize:        VPoint;
  444.  
  445.     PROCEDURE RemoveIfSubView(sbar: TSScrollBar);
  446.  
  447.         BEGIN
  448.         IF sbar <> NIL THEN RemoveSubView(sbar);
  449.         END;
  450.  
  451.     BEGIN
  452.     thePane := TView(fPanes.At(whichPane));
  453.     IF whichPane > whichSizer THEN BEGIN        { deleting pane after sizer }
  454.         changedPane := TView(fPanes.At(whichPane-1));
  455.         END
  456.     ELSE BEGIN                                    { deleting pane before sizer }
  457.         { changedPane gets re-located and expanded }
  458.         changedPane := TView(fPanes.At(whichPane+1));
  459.  
  460.         { If changedPane has become the new first pane, leave room for splitter well }
  461.         IF (whichSizer = 1) & (Member(changedPane, TScroller)) THEN BEGIN
  462.             scroller := TScroller(changedPane);
  463.             IF GetSplitDirection = h
  464.                 THEN scroller.fSBarOffsets.top := scroller.fSBarOffsets.top + fSplitter.GetThickness
  465.                 ELSE scroller.fSBarOffsets.left := scroller.fSBarOffsets.left + fSplitter.GetThickness;
  466.             (* Locate will call AdjustScrollBars *)
  467.             END;
  468.  
  469.         changedPane.Locate(thePane.fLocation.h, thePane.fLocation.v, kInvalidate);
  470.         END;
  471.  
  472.     { Expand changedPane to include oldPane's area }
  473.     newSize := MergedSize(thePane, changedPane);
  474.     changedPane.Resize(newSize.h, newSize.v, kInvalidate);
  475.     DeletePane := changedPane;                    { return the expanded view }
  476.  
  477.     RemoveSubView(thePane);
  478.     IF Member(thePane, TScroller) THEN BEGIN    { remove the TSScrollBars, too }
  479.         scroller := TScroller(thePane);
  480.         RemoveIfSubView(scroller.fScrollBars[h]);
  481.         RemoveIfSubView(scroller.fScrollBars[v]);
  482.         END;
  483.     thePane.Free;                                { frees its TSScrollBars, if any }
  484.     fPanes.AtDelete(whichPane);
  485.     fSetbacks.DeleteElementsAt(whichPane, 1);
  486.     fSizerRects.DeleteElementsAt(whichSizer, 1);
  487.     END;
  488.  
  489. FUNCTION TSizerView.FindSizerPosition(VAR itsLocation: VCoordinate): INTEGER;
  490. { Given the desired coordinate for a new sizer rectangle, return its position
  491.   (index) in the list of sizers, modifying itsLocation if necessary. }
  492.  
  493.     VAR
  494.         sizers:                INTEGER;
  495.         itsPosition:        INTEGER;
  496.         s:                    INTEGER;
  497.         firstSizerCoord:    VCoordinate;
  498.         lastSizerCoord:        VCoordinate;
  499.  
  500.     BEGIN
  501.     sizers := GetNumberOfSizers;
  502.     itsPosition := 0;
  503.     s := 1;
  504.     REPEAT
  505.         firstSizerCoord := GetSizerCoord(s, kGetMinCoord);
  506.         lastSizerCoord := GetSizerCoord(s, kGetMaxCoord);
  507.         IF itsLocation < firstSizerCoord THEN        { precedes sizer s }
  508.             itsPosition := s
  509.         ELSE IF itsLocation <= lastSizerCoord THEN    { in sizer s }
  510.             BEGIN
  511.             itsPosition := s+1;
  512.             itsLocation := lastSizerCoord + fMinPaneSize;
  513.             END
  514.         ELSE                                        { follows sizer s }
  515.             s := s + 1;
  516.     UNTIL (itsPosition > 0) | (s > sizers);
  517.     IF itsPosition = 0 THEN itsPosition := s;
  518.  
  519.     FindSizerPosition := itsPosition;
  520.     END;
  521.  
  522. {$S AOpen}
  523.  
  524. PROCEDURE TSizerView.InstallSetbacks(whichPane: INTEGER; itsSetbacks: VRect);
  525.  
  526.     BEGIN
  527.     fSetbacks.AtPut(whichPane, itsSetbacks);
  528.     END;
  529.  
  530. {$S ASelCommand}
  531.  
  532. FUNCTION TSizerView.DoMouseCommand(VAR theMouse: Point; VAR info: EventInfo;
  533.                                    VAR hysteresis: Point): TCommand; OVERRIDE;
  534.  
  535.     VAR
  536.         aViewSizer:         TSizerCommand;
  537.         aViewDeSizer:        TDeSizerCommand;
  538.         whichSizer:            INTEGER;
  539.  
  540.     BEGIN
  541.     whichSizer := IsPointInSizer(theMouse);
  542.     IF whichSizer = 0 THEN                { not in a sizer rectangle }
  543.         DoMouseCommand := INHERITED DoMouseCommand(theMouse, info, hysteresis)
  544.     ELSE IF fSplitter = NIL THEN BEGIN    { ordinary resize }
  545.         NEW(aViewSizer);
  546.         FailNIL(aViewSizer);
  547.         aViewSizer.ISizerCommand(SELF, whichSizer, GetSplitDirection);
  548.         DoMouseCommand := aViewSizer;
  549.         END
  550.     ELSE BEGIN                            { resize or delete pane }
  551.         NEW(aViewDeSizer);
  552.         FailNIL(aViewDeSizer);
  553.         aViewDeSizer.IDeSizerCommand(SELF, whichSizer, GetSplitDirection);
  554.         DoMouseCommand := aViewDeSizer;
  555.         END;
  556.     END;
  557.  
  558. {$S ARes}
  559.  
  560. FUNCTION TSizerView.DoSetCursor(localPoint: Point; cursorRgn: RgnHandle): BOOLEAN; OVERRIDE;
  561.  
  562.     VAR
  563.         sizingCursNum:        Integer;
  564.  
  565.     BEGIN
  566.     IF IsPointInSizer(localPoint) > 0 THEN BEGIN
  567.         DoSetCursor := TRUE;
  568.         sizingCursNum := GetSizingCursor;
  569.         IF (GetCursor(sizingCursNum) <> NIL)
  570.             THEN SetCursor(GetCursor(sizingCursNum)^^)
  571.             ELSE SetCursor(arrow);
  572.         END
  573.     ELSE
  574.         DoSetCursor := FALSE;
  575.     END;
  576.  
  577. {$S ARes}
  578.  
  579. PROCEDURE TSizerView.Draw(area: Rect); OVERRIDE;
  580.  
  581.     VAR
  582.         bRect:                Rect;
  583.         aRect:                Rect;
  584.         tempRect:            VRect;
  585.         s:                    INTEGER;
  586.  
  587.     BEGIN
  588.     FOR s := 1 TO GetNumberOfSizers DO BEGIN            { draw each sizerRect }
  589.         tempRect := GetSizerRect(s);
  590.         VRectToRect(tempRect, aRect);
  591.         IF SectRect(area, aRect, bRect) THEN
  592.             DrawSizerRect(aRect);
  593.         END;
  594.     END;
  595.  
  596. {$S ANever}
  597.  
  598. FUNCTION TSizerView.CompareViewLocations(view1, view2: TView): CompareResult;
  599.  
  600.     BEGIN
  601.     IF qDebug THEN ProgramBreak('CompareViewLocations must be overridden!');
  602.     END;
  603.  
  604. PROCEDURE TSizerView.DrawSizerRect(aRect: Rect);
  605.  
  606.     BEGIN
  607.     IF qDebug THEN ProgramBreak('DrawSizerRect must be overridden!');
  608.     END;
  609.  
  610. FUNCTION TSizerView.GetNextSizerRect(aPane: TView): VRect;
  611.  
  612.     BEGIN
  613.     IF qDebug THEN ProgramBreak('GetNextSizerRect must be overridden!');
  614.     END;
  615.  
  616. FUNCTION TSizerView.GetSizerCoord(whichSizer: INTEGER; min: BOOLEAN): VCoordinate;
  617. { Return the left/top (min=T) or right/bottom (min=F) coordinate of the specified sizer rect.
  618.   If whichSizer is larger than the number of sizers, return the width/height of the view.
  619.   If whichSizer is 0, return 0. }
  620.  
  621.     BEGIN
  622.     IF qDebug THEN ProgramBreak('GetSizerCoord must be overridden!');
  623.     END;
  624.  
  625. FUNCTION TSizerView.GetSizerRect(whichSizer: INTEGER): VRect;
  626.  
  627.     BEGIN
  628.     IF qDebug THEN ProgramBreak('GetSizerRect must be overridden!');
  629.     END;
  630.  
  631. FUNCTION TSizerView.GetSizingCursor: INTEGER;
  632.  
  633.     BEGIN
  634.     IF qDebug THEN ProgramBreak('GetSizingCursor must be overridden!');
  635.     GetSizingCursor := 0;
  636.     END;
  637.  
  638. FUNCTION TSizerView.IsValidSplitPt(aPoint: VPoint): BOOLEAN;
  639.  
  640.     BEGIN
  641.     IF qDebug THEN ProgramBreak('IsValidSplitPt must be overridden!');
  642.     END;
  643.  
  644. FUNCTION TSizerView.MakeSizerRect(itsLocation: VCoordinate): VRect;
  645.  
  646.     BEGIN
  647.     IF qDebug THEN ProgramBreak('MakeSizerRect must be overridden!');
  648.     END;
  649.  
  650. PROCEDURE TSizerView.TrackConstrain(anchorPoint, previousPoint: VPoint;
  651.                                     VAR nextPoint: VPoint); OVERRIDE;
  652. { Constrain mouse tracking to my interior, allowing for the minimum pane size }
  653.  
  654.     BEGIN
  655.     IF qDebug THEN ProgramBreak('TrackConstrain must be overridden!');
  656.     END;
  657.  
  658. {$S ADoCommand}
  659.  
  660. FUNCTION TSizerView.FindPane(aView: TView): INTEGER;
  661. { Return the position (index) of aView in the fPanes list }
  662.  
  663.     BEGIN
  664.     IF aView = NIL
  665.         THEN FindPane := 0
  666.         ELSE FindPane := fPanes.GetSameItemNo(aView);
  667.     END;
  668.  
  669. FUNCTION TSizerView.FindPaneAt(theCoords: VPoint): TView;
  670. { Return the pane at the given coordinates }
  671.  
  672.     FUNCTION ContainsCoords(aView: TView): BOOLEAN;
  673.  
  674.         VAR    viewFrame:    VRect;
  675.  
  676.         BEGIN
  677.         aView.GetFrame(viewFrame);
  678.         ContainsCoords := PtInVRect(theCoords, viewFrame);
  679.         END;
  680.  
  681.     BEGIN
  682.     FindPaneAt := TView(fPanes.FirstThat(ContainsCoords));
  683.     END;
  684.  
  685. {$S AOpen}
  686. FUNCTION TSizerView.GetDefaultSizerRect(whichSizer: INTEGER): VRect;
  687.  
  688.     VAR
  689.         paneLength:            LONGINT;
  690.         dir:                VHSelect;
  691.  
  692.     BEGIN
  693.     dir := OtherDirection(GetSplitDirection);
  694.     paneLength := fSize.vh[dir] DIV GetNumberOfPanes;
  695.     GetDefaultSizerRect := MakeSizerRect(paneLength * whichSizer);
  696.     END;
  697.  
  698. {$S ADoCommand}
  699.  
  700. FUNCTION TSizerView.GetMinPaneLength: VCoordinate;
  701. { Return the minimum width/height of a pane of this view. }
  702.  
  703.     BEGIN
  704.     GetMinPaneLength := fMinPaneSize;
  705.     END;
  706.  
  707. PROCEDURE TSizerView.SetMinPaneLength(minLength: VCoordinate);
  708.  
  709.     BEGIN
  710.     fMinPaneSize := minLength;
  711.     END;
  712.  
  713. {$S ADoCommand}
  714.  
  715. FUNCTION  TSizerView.GetNumberOfPanes: INTEGER;
  716.  
  717.     BEGIN
  718.     GetNumberOfPanes := fPanes.GetSize;
  719.     END;
  720.  
  721. FUNCTION  TSizerView.GetNumberOfSizers: INTEGER;
  722.  
  723.     BEGIN
  724.     GetNumberOfSizers := fSizerRects.GetSize;
  725.     END;
  726.  
  727. {$S ARes}
  728.  
  729. FUNCTION TSizerView.GetSizerThickness: INTEGER;
  730.  
  731.     BEGIN
  732.     GetSizerThickness := fSizerThickness;
  733.     END;
  734.  
  735. PROCEDURE TSizerView.SetSizerThickness(thickness: INTEGER);
  736.  
  737.     BEGIN
  738.     fSizerThickness := thickness;
  739.     END;
  740.  
  741. {$S ARes}
  742.  
  743. FUNCTION TSizerView.GetSplitDirection: VHSelect;
  744.  
  745.     BEGIN
  746.     GetSplitDirection := h;
  747.     END;
  748.  
  749. {$S ARes}
  750. PROCEDURE TSizerView.InvalidateFocus; OVERRIDE;
  751.  
  752.     BEGIN
  753.     gFocusedView := NIL;        { Eschew traversing all the subviews; just do it! }
  754.     END;
  755.  
  756. {$S ARes}
  757. FUNCTION TSizerView.IsPointInSizer(localPoint: Point): INTEGER;
  758. { Return the number of the sizer rect the point is in, or 0 if none. }
  759.  
  760.     VAR
  761.         aVPt:                VPoint;
  762.         tempRect:            VRect;
  763.         s:                    INTEGER;
  764.  
  765.     BEGIN
  766.     IsPointInSizer := 0;
  767.     PtToVPt(localPoint, aVPt);
  768.     FOR s := 1 TO GetNumberOfSizers DO BEGIN
  769.         tempRect := GetSizerRect(s);
  770.         IF PtInVRect(aVPt, tempRect) THEN BEGIN    { mouse is in sizer }
  771.             IsPointInSizer := s;
  772.             LEAVE;
  773.             END;
  774.         END;
  775.     END;
  776.  
  777. {$S APane}
  778. FUNCTION TSizerView.MergedSize(oldPane, changedPane: TView): VPoint;
  779. { Return the combined size of oldPane and changedPane }
  780.  
  781.     VAR
  782.         newSize:            VPoint;
  783.         myDir, opDir:        VHSelect;
  784.         sbar:                TSScrollBar;
  785.  
  786.     BEGIN
  787.     newSize := changedPane.fSize;
  788.     myDir := GetSplitDirection;
  789.     opDir := OtherDirection(myDir);
  790.     newSize.vh[opDir] := newSize.vh[opDir] + oldPane.fSize.vh[opDir] + fSizerThickness;
  791.     IF Member(oldPane, TScroller) THEN BEGIN    { allow for disappearing scrollbars }
  792.         sbar := TScroller(oldPane).fScrollBars[myDir];
  793.         IF sbar <> NIL THEN
  794.             newSize.vh[opDir] := newSize.vh[opDir] + sbar.fSize.vh[opDir] - 1;
  795.         END;
  796.     MergedSize := newSize;
  797.     END;
  798.  
  799. {$S ANonRes}
  800.  
  801. PROCEDURE TSizerView.SetPane(whichSizer: INTEGER; itsSizerRect: VRect);
  802.  
  803.     BEGIN
  804.     IF qDebug THEN ProgramBreak('SetPane must be overridden!');
  805.     END;
  806.  
  807. PROCEDURE TSizerView.SetPanes(newSizerRects: TVRectList; invalidate: BOOLEAN);
  808.  
  809.     BEGIN
  810.     IF qDebug THEN ProgramBreak('SetPanes must be overridden!');
  811.     END;
  812.  
  813. PROCEDURE TSizerView.SetSizerRect(whichSizer: INTEGER; itsSizerRect: VRect);
  814.  
  815.     VAR
  816.         aVRect:             VRect;
  817.         localRect:            VRect;
  818.         r:                    Rect;
  819.  
  820.     BEGIN
  821.     localRect := itsSizerRect;
  822.     aVRect := GetSizerRect(whichSizer);
  823.     IF IsShown & Focus THEN BEGIN                        { code from TView.InvalidVRect }
  824.         ViewToQDRect(localRect, r);
  825.         VisibleRect(r);
  826.         IF NOT EmptyRect(r) THEN
  827.             InvalidateFocusedRect(r);
  828.         ViewToQDRect(aVRect, r);
  829.         VisibleRect(r);
  830.         IF NOT EmptyRect(r) THEN
  831.             InvalidateFocusedRect(r);
  832.         END;
  833.     fSizerRects.AtPut(whichSizer, itsSizerRect);
  834.     END;
  835.  
  836. {$S ANonRes}
  837.  
  838. PROCEDURE TSizerView.SuperViewChangedSize(delta: VPoint; invalidate: BOOLEAN); OVERRIDE;
  839.  
  840.     VAR
  841.         lastCommand: TCommand;
  842.  
  843.     BEGIN
  844.     lastCommand := GetLastCommand;
  845.     IF lastCommand <> NIL THEN
  846.         IF (lastCommand.fCmdNumber = cSizeViews) & (lastCommand.fView = SELF) THEN
  847.             CommitLastCommand;
  848.     INHERITED SuperViewChangedSize(delta, invalidate);
  849.     END;
  850.  
  851.  
  852. {$S AFields}
  853.  
  854. PROCEDURE TSizerView.Fields(PROCEDURE DoToField(fieldName: Str255; fieldAddr: Ptr;
  855.                                                 fieldType: INTEGER)); OVERRIDE;
  856.  
  857.     BEGIN
  858.     DoToField('TSizerView', NIL, bClass);
  859.     DoToField('fPanes', @fPanes, bObject);
  860.     DoToField('fSetbacks', @fSetbacks, bObject);
  861.     DoToField('fSizerRects', @fSizerRects, bObject);
  862.     DoToField('fMinPaneSize', @fMinPaneSize, bLongint);
  863.     DoToField('fSizerThickness', @fSizerThickness, bInteger);
  864.     DoToField('fSplitter', @fSplitter, bObject);
  865.     INHERITED Fields(DoToField);
  866.     END;
  867.  
  868. {-------------------------- THorizontalSizer ----------------------}
  869.  
  870. {$S AOpen}
  871.  
  872. FUNCTION THorizontalSizer.CompareViewLocations(view1, view2: TView): CompareResult; OVERRIDE;
  873.  
  874.     VAR
  875.         frame1, frame2:    VRect;
  876.  
  877.     BEGIN
  878.     view1.GetFrame(frame1);
  879.     view2.GetFrame(frame2);
  880.     IF frame1.top > frame2.top THEN
  881.         CompareViewLocations := kItem1GreaterThanItem2
  882.     ELSE IF frame1.top < frame2.top THEN
  883.         CompareViewLocations := kItem1LessThanItem2
  884.     ELSE
  885.         CompareViewLocations := kItem1EqualItem2;
  886.     END;
  887.  
  888. {$S ARes}
  889.  
  890. PROCEDURE THorizontalSizer.DrawSizerRect(aRect: Rect); OVERRIDE;
  891.  
  892.     BEGIN
  893.     WITH aRect DO BEGIN    { horizontal splitter }
  894.         MoveTo(left, top);
  895.         LineTo(right, top);
  896.         MoveTo(left, bottom-1);
  897.         LineTo(right, bottom-1);
  898.         END;
  899.     END;
  900.  
  901. {$S AOpen}
  902. FUNCTION THorizontalSizer.GetNextSizerRect(aPane: TView): VRect; OVERRIDE;
  903.  
  904.     VAR
  905.         vr:        VRect;
  906.  
  907.     BEGIN
  908.     aPane.GetFrame(vr);
  909.     GetNextSizerRect := MakeSizerRect(vr.bottom);
  910.     END;
  911.  
  912. {$S ADoCommand}
  913.  
  914. FUNCTION THorizontalSizer.GetSizerCoord(whichSizer: INTEGER;
  915.                                         min: BOOLEAN): VCoordinate; OVERRIDE;
  916.  
  917.     VAR
  918.         aSizerRect:        VRect;
  919.  
  920.     BEGIN
  921.     IF whichSizer = 0 THEN
  922.         GetSizerCoord := 0
  923.     ELSE IF whichSizer > fSizerRects.GetSize THEN
  924.         GetSizerCoord := fSize.v
  925.     ELSE BEGIN
  926.         aSizerRect := fSizerRects.At(whichSizer);
  927.         IF min
  928.             THEN GetSizerCoord := aSizerRect.top
  929.             ELSE GetSizerCoord := aSizerRect.bottom;
  930.         END;
  931.     END;
  932.  
  933. {$S ARes}
  934.  
  935. FUNCTION THorizontalSizer.GetSizingCursor: INTEGER; OVERRIDE;
  936.  
  937.     BEGIN
  938.     GetSizingCursor := kHorzSizingCursor;
  939.     END;
  940.  
  941. FUNCTION THorizontalSizer.GetSizerRect(whichSizer: INTEGER): VRect; OVERRIDE;
  942.  
  943.     VAR
  944.         vr:        VRect;
  945.  
  946.     BEGIN
  947.     IF whichSizer = 0 THEN BEGIN
  948.         SetVRect(vr, 0, 0, fSize.h, 0);
  949.         END
  950.     ELSE IF whichSizer > GetNumberOfSizers THEN BEGIN
  951.         SetVRect(vr, 0, fSize.v, fSize.h, fSize.v);
  952.         END
  953.     ELSE
  954.         vr := fSizerRects.At(whichSizer);
  955.  
  956.     GetSizerRect := vr;
  957.     END;
  958.  
  959. {$S ADoCommand}
  960. FUNCTION THorizontalSizer.IsValidSplitPt(aPoint: VPoint): BOOLEAN; OVERRIDE;
  961.  
  962.     BEGIN
  963.     IsValidSplitPt := (aPoint.v >= fMinPaneSize) &
  964.                       (aPoint.v <= fSize.v - fMinPaneSize - fSizerThickness);
  965.     END;
  966.  
  967. {$S ARes}
  968.  
  969. FUNCTION THorizontalSizer.MakeSizerRect(itsLocation: VCoordinate): VRect; OVERRIDE;
  970.  
  971.     VAR
  972.         aVRect:        VRect;
  973.  
  974.     BEGIN
  975.     SetVRect(aVRect, 0, itsLocation, fSize.h, itsLocation+fSizerThickness);
  976.     MakeSizerRect := aVRect;
  977.     END;
  978.  
  979. {$S ANonRes}
  980.  
  981. PROCEDURE THorizontalSizer.Resize(width, height: VCoordinate; invalidate: BOOLEAN); OVERRIDE;
  982.  
  983.     VAR
  984.         aSizerRect:         VRect;
  985.         oldHeight:            VCoordinate;
  986.         paneHeight:            VCoordinate;
  987.         previous:             VCoordinate;
  988.         panes:                INTEGER;
  989.         sizers:                INTEGER;
  990.         checkMinimum:        BOOLEAN;
  991.         newSizerRects:        TVRectList;
  992.         s:                    INTEGER;
  993.         delta:                VPoint;
  994.  
  995.     PROCEDURE NotifyNonPanes(theSubView: TView);
  996.  
  997.         BEGIN
  998.         IF fPanes.GetSameItemNo(theSubView) = 0 THEN    { not a pane }
  999.             theSubView.SuperViewChangedSize(delta, invalidate);
  1000.         END;
  1001.  
  1002.     BEGIN
  1003.     sizers := GetNumberOfSizers;
  1004.     panes := sizers + 1;
  1005.     checkMinimum := (((panes*kMinSizerPane) + (sizers*fSizerThickness)) <= height);
  1006.     {$IFC qDebug}
  1007.         IF NOT checkMinimum THEN
  1008.             ProgramBreak('THorizontalSizer.Resize: height too small for panes!!');
  1009.     {$ENDC}
  1010.  
  1011.     IF sizers = 0 THEN
  1012.         INHERITED Resize(width, height, invalidate)
  1013.     ELSE BEGIN
  1014.         oldHeight := fSize.v;
  1015.         IF (fSize.h <> width) OR (oldHeight <> height) THEN BEGIN
  1016.         (*    INHERITED Resize(width, height, FALSE);    { we’ll notify the subviews ourself } *)
  1017.             SetVPt(delta, width - fSize.h, height - fSize.v);
  1018.             fSize.h := width;
  1019.             fSize.v := height;
  1020.             InvalidateFocus;                                {Must re-focus because size changed}
  1021.             gApplication.InvalidateCursorRgn;                {Must re-calc cursor rgn.}
  1022.     
  1023.             IF sizers > 0 THEN BEGIN                        { subviews have been installed }
  1024.                 newSizerRects := TVRectList(fSizerRects.Clone);
  1025.                 IF oldHeight = height THEN BEGIN            { adjust width only }
  1026.                     FOR s := 1 TO sizers DO
  1027.                         newSizerRects.AtCoordPut(s, kRightCoord, width);
  1028.                     END
  1029.                 ELSE BEGIN                                    { need to adjust height as well }
  1030.                     previous := 0;
  1031.                     FOR s := 1 TO sizers DO BEGIN            { adjust each sizer rect }
  1032.                         aSizerRect := GetSizerRect(s);
  1033.                         paneHeight := aSizerRect.top - previous;
  1034.                         paneHeight := FixMul(paneHeight, FixDiv(height, oldHeight));
  1035.                         IF checkMinimum & (paneHeight < kMinSizerPane) THEN
  1036.                             paneHeight := kMinSizerPane;
  1037.                         SetVRect(aSizerRect, 0, previous + paneHeight,
  1038.                                              width, previous + paneHeight + fSizerThickness);
  1039.                         newSizerRects.AtPut(s, aSizerRect);
  1040.                         previous := aSizerRect.bottom;
  1041.                         END;
  1042.                     IF checkMinimum THEN BEGIN                { check last pane }
  1043.                         previous := height;
  1044.                         s := sizers;
  1045.                         REPEAT
  1046.                             aSizerRect := newSizerRects.At(s);
  1047.                             paneHeight := previous - aSizerRect.bottom;
  1048.                             IF paneHeight >= kMinSizerPane THEN LEAVE;
  1049.                             { re-adjust sizer rect }
  1050.                             SetVRect(aSizerRect, 0, previous - kMinSizerPane - fSizerThickness,
  1051.                                                  width, previous - kMinSizerPane);
  1052.                             previous := aSizerRect.top;
  1053.                             s := s - 1;
  1054.                         UNTIL s = 0;
  1055.                         END;
  1056.                     END;
  1057.                 SetPanes(newSizerRects, invalidate);
  1058.                 newSizerRects.Free;                            { discard temp sizerRects object }
  1059.                 END;
  1060.     
  1061.             EachSubView(NotifyNonPanes);
  1062.             END;
  1063.         END;
  1064.     END;
  1065.  
  1066. {$S ADoCommand}
  1067.  
  1068. PROCEDURE THorizontalSizer.SetPane(whichSizer: INTEGER; itsSizerRect: VRect); OVERRIDE;
  1069. { A single sizer rectangle has moved, so adjust the panes above and below it }
  1070.  
  1071.     VAR
  1072.         oldSizerRect:        VRect;
  1073.         vp:                    VPoint;
  1074.         setbacks:             VRect;
  1075.         deltaV:                VCoordinate;
  1076.         firstView:            TView;
  1077.         secondView:            TView;
  1078.  
  1079.     BEGIN
  1080.     oldSizerRect := GetSizerRect(whichSizer);
  1081.     deltaV := itsSizerRect.top - oldSizerRect.top;
  1082.     SetSizerRect(whichSizer, itsSizerRect);
  1083.  
  1084.     firstView := TView(fPanes.At(whichSizer));
  1085.     vp := firstView.fSize;    (* can’t use GetExtent ’cause TScrollers add in translation *)
  1086.     firstView.Resize(vp.h, vp.v + deltaV, kInvalidate);
  1087.  
  1088.     secondView := TView(fPanes.At(whichSizer+1));
  1089.     vp := secondView.fSize;
  1090.     secondView.Resize(vp.h, vp.v - deltaV, kInvalidate);
  1091.     setbacks := fSetbacks.At(whichSizer+1);
  1092.     vp := secondView.fLocation;
  1093.     secondView.Locate(vp.h, itsSizerRect.bottom + setbacks.top, kInvalidate);
  1094.     END;
  1095.  
  1096. {$S ANonRes}
  1097.  
  1098. PROCEDURE THorizontalSizer.SetPanes(newSizerRects: TVRectList; invalidate: BOOLEAN); OVERRIDE;
  1099.  
  1100.     VAR
  1101.         itsSizerRect:        VRect;
  1102.         vr:                    VRect;
  1103.         setbacks:             VRect;
  1104.         theView:            TView;
  1105.         s:                    INTEGER;
  1106.         sizers:                INTEGER;
  1107.         pTop:                VCoordinate;
  1108.         pBottom:            VCoordinate;
  1109.  
  1110.     BEGIN
  1111.     sizers := newSizerRects.GetSize;
  1112.     pTop := 0;
  1113.     FOR s := 1 TO sizers+1 DO BEGIN
  1114.         IF s > sizers THEN
  1115.             pBottom := fSize.v                        { last pane }
  1116.         ELSE BEGIN                                    { not the last pane }
  1117.             IF invalidate THEN BEGIN                { invalidate old sizer rectangle }
  1118.                 itsSizerRect := GetSizerRect(s);
  1119.                 InvalidVRect(itsSizerRect);
  1120.                 END;
  1121.             itsSizerRect := newSizerRects.At(s);
  1122.             IF invalidate THEN                        { invalidate new sizer rectangle }
  1123.                 InvalidVRect(itsSizerRect);
  1124.             pBottom := itsSizerRect.top;
  1125.             fSizerRects.AtPut(s, itsSizerRect);
  1126.             END;                    
  1127.         theView := TView(fPanes.At(s));
  1128.         setbacks := fSetbacks.At(s);
  1129.         theView.Locate(itsSizerRect.left + setbacks.left, pTop + setbacks.top, invalidate);
  1130.         theView.Resize(itsSizerRect.right - setbacks.left - setbacks.right,
  1131.                        pBottom - pTop - setbacks.top - setbacks.bottom, invalidate);
  1132.         pTop := itsSizerRect.bottom;
  1133.         END;
  1134. (*    IF invalidate THEN ForceRedraw; *)
  1135.     END;
  1136.  
  1137. {$S ADoCommand}
  1138.  
  1139. PROCEDURE THorizontalSizer.TrackConstrain(anchorPoint, previousPoint: VPoint;
  1140.                                           VAR nextPoint: VPoint); OVERRIDE;
  1141. { Constrain mouse tracking to my interior, allowing for the minimum pane size }
  1142.  
  1143.     VAR
  1144.         theMin:                LONGINT;
  1145.         theMax:                LONGINT;
  1146.  
  1147.     BEGIN
  1148.     theMin := fMinPaneSize;
  1149.     theMax := fSize.v - theMin;
  1150.     IF nextPoint.v < theMin
  1151.         THEN nextPoint.v := theMin
  1152.         ELSE nextPoint.v := Min(nextPoint.v, theMax);
  1153.     END;
  1154.  
  1155. {-------------------------- TVerticalSizer ----------------------}
  1156.  
  1157. {$S AOpen}
  1158.  
  1159. FUNCTION TVerticalSizer.CompareViewLocations(view1, view2: TView): CompareResult; OVERRIDE;
  1160.  
  1161.     VAR
  1162.         frame1, frame2:    VRect;
  1163.  
  1164.     BEGIN
  1165.     view1.GetFrame(frame1);
  1166.     view2.GetFrame(frame2);
  1167.     IF frame1.left > frame2.left THEN
  1168.         CompareViewLocations := kItem1GreaterThanItem2
  1169.     ELSE IF frame1.left < frame2.left THEN
  1170.         CompareViewLocations := kItem1LessThanItem2
  1171.     ELSE
  1172.         CompareViewLocations := kItem1EqualItem2;
  1173.     END;
  1174.  
  1175. {$S ARes}
  1176.  
  1177. PROCEDURE TVerticalSizer.DrawSizerRect(aRect: Rect); OVERRIDE;
  1178.  
  1179.     BEGIN
  1180.     WITH aRect DO BEGIN
  1181.         MoveTo(left, top);
  1182.         LineTo(left, bottom);
  1183.         MoveTo(right-1, top);
  1184.         LineTo(right-1, bottom);
  1185.         END;
  1186.     END;
  1187.  
  1188. {$S AOpen}
  1189. FUNCTION TVerticalSizer.GetNextSizerRect(aPane: TView): VRect; OVERRIDE;
  1190.  
  1191.     VAR
  1192.         vr:        VRect;
  1193.  
  1194.     BEGIN
  1195.     aPane.GetFrame(vr);
  1196.     GetNextSizerRect := MakeSizerRect(vr.right);
  1197.     END;
  1198.  
  1199. {$S ADoCommand}
  1200.  
  1201. FUNCTION TVerticalSizer.GetSizerCoord(whichSizer: INTEGER;
  1202.                                       min: BOOLEAN): VCoordinate; OVERRIDE;
  1203.  
  1204.     VAR
  1205.         aSizerRect:        VRect;
  1206.  
  1207.     BEGIN
  1208.     IF whichSizer = 0 THEN
  1209.         GetSizerCoord := 0
  1210.     ELSE IF whichSizer > fSizerRects.GetSize THEN
  1211.         GetSizerCoord := fSize.h
  1212.     ELSE BEGIN
  1213.         aSizerRect := fSizerRects.At(whichSizer);
  1214.         IF min
  1215.             THEN GetSizerCoord := aSizerRect.left
  1216.             ELSE GetSizerCoord := aSizerRect.right;
  1217.         END;
  1218.     END;
  1219.  
  1220. {$S ARes}
  1221.  
  1222. FUNCTION TVerticalSizer.GetSizingCursor: INTEGER; OVERRIDE;
  1223.  
  1224.     BEGIN
  1225.     GetSizingCursor := kVertSizingCursor;
  1226.     END;
  1227.  
  1228. FUNCTION TVerticalSizer.GetSizerRect(whichSizer: INTEGER): VRect; OVERRIDE;
  1229.  
  1230.     VAR
  1231.         vr:        VRect;
  1232.  
  1233.     BEGIN
  1234.     IF whichSizer = 0 THEN BEGIN
  1235.         SetVRect(vr, 0, 0, 0, fSize.v);
  1236.         END
  1237.     ELSE IF whichSizer > GetNumberOfSizers THEN BEGIN
  1238.         SetVRect(vr, fSize.h, 0, fSize.h, fSize.v);
  1239.         END
  1240.     ELSE
  1241.         vr := fSizerRects.At(whichSizer);
  1242.  
  1243.     GetSizerRect := vr;
  1244.     END;
  1245.  
  1246. {$S ARes}
  1247. FUNCTION TVerticalSizer.GetSplitDirection: VHSelect; OVERRIDE;
  1248.  
  1249.     BEGIN
  1250.     GetSplitDirection := v;
  1251.     END;
  1252.  
  1253. {$S ADoCommand}
  1254. FUNCTION TVerticalSizer.IsValidSplitPt(aPoint: VPoint): BOOLEAN; OVERRIDE;
  1255.  
  1256.     BEGIN
  1257.     IsValidSplitPt := (aPoint.h >= fMinPaneSize) &
  1258.                       (aPoint.h <= fSize.h - fMinPaneSize - fSizerThickness);
  1259.     END;
  1260.  
  1261. {$S ARes}
  1262. FUNCTION TVerticalSizer.MakeSizerRect(itsLocation: VCoordinate): VRect; OVERRIDE;
  1263.  
  1264.     VAR
  1265.         aVRect:        VRect;
  1266.  
  1267.     BEGIN
  1268.     SetVRect(aVRect, itsLocation, 0, itsLocation+fSizerThickness, fSize.v);
  1269.     MakeSizerRect := aVRect;
  1270.     END;
  1271.  
  1272. {$S ANonRes}
  1273. PROCEDURE TVerticalSizer.Resize(width, height: VCoordinate; invalidate: BOOLEAN); OVERRIDE;
  1274.  
  1275.     VAR
  1276.         aSizerRect:         VRect;
  1277.         oldWidth:            VCoordinate;
  1278.         paneWidth:            VCoordinate;
  1279.         previous:             VCoordinate;
  1280.         panes:                INTEGER;
  1281.         sizers:                INTEGER;
  1282.         checkMinimum:        BOOLEAN;
  1283.         newSizerRects:        TVRectList;
  1284.         s:                    INTEGER;
  1285.         delta:                VPoint;
  1286.  
  1287.     PROCEDURE NotifyNonPanes(theSubView: TView);
  1288.  
  1289.         BEGIN
  1290.         IF fPanes.GetSameItemNo(theSubView) = 0 THEN    { not a pane }
  1291.             theSubView.SuperViewChangedSize(delta, invalidate);
  1292.         END;
  1293.  
  1294.     BEGIN
  1295.     sizers := GetNumberOfSizers;
  1296.     panes := sizers + 1;
  1297.     checkMinimum := (((panes*kMinSizerPane) + (sizers*fSizerThickness)) <= width);
  1298.     {$IFC qDebug}
  1299.         IF NOT checkMinimum THEN
  1300.             ProgramBreak('TVerticalSizer.Resize: width too small for panes!!');
  1301.     {$ENDC}
  1302.  
  1303.     IF sizers = 0 THEN
  1304.         INHERITED Resize(width, height, invalidate)
  1305.     ELSE BEGIN
  1306.         oldWidth := fSize.h;
  1307.         IF (oldWidth <> width) OR (fSize.v <> height) THEN BEGIN
  1308.         (*    INHERITED Resize(width, height, FALSE);    { we’ll notify the subviews ourself } *)
  1309.             SetVPt(delta, width - fSize.h, height - fSize.v);
  1310.             fSize.h := width;
  1311.             fSize.v := height;
  1312.             InvalidateFocus;                                {Must re-focus because size changed}
  1313.             gApplication.InvalidateCursorRgn;                {Must re-calc cursor rgn.}
  1314.     
  1315.             IF sizers > 0 THEN BEGIN                        { subviews have been installed }
  1316.                 newSizerRects := TVRectList(fSizerRects.Clone);
  1317.                 IF oldWidth = width THEN BEGIN                { adjust height only }
  1318.                     FOR s := 1 TO sizers DO
  1319.                         newSizerRects.AtCoordPut(s, kBottomCoord, height);
  1320.                     END
  1321.                 ELSE BEGIN                                    { need to adjust width as well }
  1322.                     previous := 0;
  1323.                     FOR s := 1 TO sizers DO BEGIN            { adjust each sizer rect }
  1324.                         aSizerRect := GetSizerRect(s);
  1325.                         paneWidth := aSizerRect.left - previous;
  1326.                         paneWidth := FixMul(paneWidth, FixDiv(width, oldWidth));
  1327.                         IF checkMinimum & (paneWidth < kMinSizerPane) THEN
  1328.                             paneWidth := kMinSizerPane;
  1329.                         SetVRect(aSizerRect, previous + paneWidth, 0,
  1330.                                              previous + paneWidth + fSizerThickness, height);
  1331.                         newSizerRects.AtPut(s, aSizerRect);
  1332.                         previous := aSizerRect.right;
  1333.                         END;
  1334.                     IF checkMinimum THEN BEGIN                { check last pane }
  1335.                         previous := width;
  1336.                         s := sizers;
  1337.                         REPEAT
  1338.                             aSizerRect := newSizerRects.At(s);
  1339.                             paneWidth := previous - aSizerRect.right;
  1340.                             IF paneWidth >= kMinSizerPane THEN LEAVE;
  1341.                             { re-adjust sizer rect }
  1342.                             SetVRect(aSizerRect, previous - kMinSizerPane - fSizerThickness, 0,
  1343.                                                  previous - kMinSizerPane, height);
  1344.                             newSizerRects.AtPut(s, aSizerRect);
  1345.                             previous := aSizerRect.left;
  1346.                             s := s - 1;
  1347.                         UNTIL s = 0;
  1348.                         END;
  1349.                     END;    { adjust width & height }
  1350.                 SetPanes(newSizerRects, invalidate);
  1351.                 newSizerRects.Free;                            { discard temp sizerRects object }
  1352.                 END;
  1353.     
  1354.             EachSubView(NotifyNonPanes);
  1355.             END;
  1356.         END;
  1357.     END;    { TVerticalSizer.Resize }
  1358.  
  1359. {$S ADoCommand}
  1360.  
  1361. PROCEDURE TVerticalSizer.SetPane(whichSizer: INTEGER; itsSizerRect: VRect); OVERRIDE;
  1362. { A single sizer rectangle has moved, so adjust the panes on either side of it }
  1363.  
  1364.     VAR
  1365.         oldSizerRect:        VRect;
  1366.         vp:                    VPoint;
  1367.         setbacks:             VRect;
  1368.         deltaH:                VCoordinate;
  1369.         firstView:            TView;
  1370.         secondView:            TView;
  1371.  
  1372.     BEGIN
  1373.     oldSizerRect := GetSizerRect(whichSizer);
  1374.     deltaH := itsSizerRect.left - oldSizerRect.left;
  1375.     SetSizerRect(whichSizer, itsSizerRect);
  1376.  
  1377.     firstView := TView(fPanes.At(whichSizer));
  1378.     vp := firstView.fSize;    (* can’t use GetExtent ’cause TScrollers add in translation *)
  1379.     firstView.Resize(vp.h + deltaH, vp.v, kInvalidate);
  1380.  
  1381.     secondView := TView(fPanes.At(whichSizer+1));
  1382.     vp := secondView.fSize;
  1383.     secondView.Resize(vp.h - deltaH, vp.v, kInvalidate);
  1384.     setbacks := fSetbacks.At(whichSizer+1);
  1385.     vp := secondView.fLocation;
  1386.     secondView.Locate(itsSizerRect.right + setbacks.left, vp.v, kInvalidate);
  1387.     END;
  1388.  
  1389. {$S ANonRes}
  1390.  
  1391. PROCEDURE TVerticalSizer.SetPanes(newSizerRects: TVRectList; invalidate: BOOLEAN); OVERRIDE;
  1392.  
  1393.     VAR
  1394.         itsSizerRect:        VRect;
  1395.         vr:                    VRect;
  1396.         setbacks:             VRect;
  1397.         theView:            TView;
  1398.         s:                    INTEGER;
  1399.         sizers:                INTEGER;
  1400.         pLeft:                VCoordinate;
  1401.         pRight:                VCoordinate;
  1402.  
  1403.     BEGIN
  1404.     sizers := newSizerRects.GetSize;
  1405.     pLeft := 0;
  1406.     FOR s := 1 TO sizers+1 DO BEGIN
  1407.         IF s <= sizers THEN BEGIN                    { not the last pane }
  1408.             IF invalidate THEN BEGIN                { invalidate old sizer rectangle }
  1409.                 itsSizerRect := GetSizerRect(s);
  1410.                 InvalidVRect(itsSizerRect);
  1411.                 END;
  1412.             itsSizerRect := newSizerRects.At(s);
  1413.             IF invalidate THEN                        { invalidate new sizer rectangle }
  1414.                 InvalidVRect(itsSizerRect);
  1415.             pRight := itsSizerRect.left;
  1416.             fSizerRects.AtPut(s, itsSizerRect);
  1417.             END
  1418.         ELSE                                        { last pane }
  1419.             pRight := fSize.h;
  1420.         theView := TView(fPanes.At(s));
  1421.         setbacks := fSetbacks.At(s);
  1422.         theView.Locate(pLeft + setbacks.left, itsSizerRect.top + setbacks.top, invalidate);
  1423.         theView.Resize(pRight - pLeft - setbacks.left - setbacks.right,
  1424.                        itsSizerRect.bottom - setbacks.top - setbacks.bottom, invalidate);
  1425.         pLeft := itsSizerRect.right;
  1426.         END;
  1427. (*    IF invalidate THEN ForceRedraw; *)
  1428.     END;
  1429.  
  1430. {$S ADoCommand}
  1431.  
  1432. PROCEDURE TVerticalSizer.TrackConstrain(anchorPoint, previousPoint: VPoint;
  1433.                                         VAR nextPoint: VPoint); OVERRIDE;
  1434. { Constrain mouse tracking to my interior, allowing for the minimum pane size }
  1435.  
  1436.     VAR
  1437.         theMin:                LONGINT;
  1438.         theMax:                LONGINT;
  1439.  
  1440.     BEGIN
  1441.     theMin := fMinPaneSize;
  1442.     theMax := fSize.h - theMin;
  1443.     IF nextPoint.h < theMin
  1444.         THEN nextPoint.h := theMin
  1445.         ELSE nextPoint.h := Min(nextPoint.h, theMax);
  1446.     END;
  1447.  
  1448.  
  1449. {-------------------------- TSizerCommand ----------------------}
  1450.  
  1451. {$S ASelCommand}
  1452.  
  1453. PROCEDURE TSizerCommand.ISizerCommand(itsSizerView: TSizerView; whichSizer: INTEGER;
  1454.                                       whichWay: VHSelect);
  1455.  
  1456.     VAR
  1457.         sizerRect:             VRect;
  1458.  
  1459.     BEGIN
  1460.     ICommand(cSizeViews, itsSizerView.fDocument, itsSizerView, NIL);
  1461.     fCausesChange := FALSE;
  1462.     fConstrainsMouse := TRUE;
  1463.     fSizerView := itsSizerView;
  1464.     fSplitDir := whichWay;
  1465.     fWhichSizer := whichSizer;
  1466.  
  1467.     sizerRect := fSizerView.GetSizerRect(whichSizer);
  1468.     fOldSizerRect := sizerRect;
  1469.     IF fSplitDir = kSplitVertically
  1470.         THEN fNewEdge := sizerRect.left
  1471.         ELSE fNewEdge := sizerRect.top;
  1472.     END;                                        { TSizerCommand.ISizerCommand }
  1473.  
  1474. {$S ADoCommand}
  1475.  
  1476. FUNCTION TSizerCommand.TrackMouse(aTrackPhase: TrackPhase; VAR anchorPoint, previousPoint,
  1477.                                   nextPoint: VPoint; mouseDidMove: BOOLEAN): TCommand; OVERRIDE;
  1478. { Arguments are in fSizerView coordinates }
  1479.  
  1480.     VAR
  1481.         aVRect:             VRect;
  1482.  
  1483.     BEGIN
  1484.     TrackMouse := SELF;                            { keep on trackin’ }
  1485.     IF fSplitDir = kSplitVertically
  1486.         THEN fNewEdge := nextPoint.h
  1487.         ELSE fNewEdge := nextPoint.v;
  1488.  
  1489.     IF aTrackPhase = trackRelease THEN BEGIN
  1490.         aVRect := fOldSizerRect;
  1491.         IF PtInVRect(nextPoint, aVRect) THEN
  1492.             TrackMouse := NIL;
  1493.         END;
  1494.     END;                                        { TSizerCommand.TrackMouse }
  1495.  
  1496. {$S ADoCommand}
  1497.  
  1498. PROCEDURE TSizerCommand.TrackFeedback(anchorPoint, nextPoint: VPoint; turnItOn,
  1499.                                       mouseDidMove: BOOLEAN); OVERRIDE;
  1500.  
  1501.     VAR
  1502.         viewedRect:         Rect;
  1503.         pState:             PenState;
  1504.         aQDPt:                Point;
  1505.  
  1506.     BEGIN
  1507.     IF mouseDidMove THEN
  1508.         BEGIN
  1509.         GetPenState(pState);
  1510.         SetPenForFeedback(nextPoint);
  1511.  
  1512.         fSizerView.GetQDExtent(viewedRect);
  1513.  
  1514.         IF fSplitDir = kSplitVertically THEN
  1515.             BEGIN
  1516.             MoveTo(nextPoint.h, viewedRect.top);
  1517.             Line(0, viewedRect.bottom - viewedRect.top);
  1518.             END
  1519.         ELSE
  1520.             BEGIN
  1521.             MoveTo(viewedRect.left, nextPoint.v);
  1522.             Line(viewedRect.right - viewedRect.left, 0);
  1523.             END;
  1524.         SetPenState(pState);
  1525.         END;
  1526.     END;                                                { TSizerCommand.TrackFeedback }
  1527.  
  1528. {$S ADoCommand}
  1529.  
  1530. PROCEDURE TSizerCommand.TrackConstrain(anchorPoint, previousPoint: VPoint;
  1531.                                        VAR nextPoint: VPoint); OVERRIDE;
  1532.  
  1533.     VAR
  1534.         theMin:                LONGINT;
  1535.         theMax:                LONGINT;
  1536.         temp:                LONGINT;
  1537.         minSizerPane:        VCoordinate;
  1538.  
  1539.     BEGIN
  1540.     minSizerPane := fSizerView.GetMinPaneLength;
  1541.     theMin := (fWhichSizer * minSizerPane) + ((fWhichSizer-1) * fSizerView.GetSizerThickness);
  1542.     { don’t let sizer rect overlap preceding ones }
  1543.     temp := fSizerView.GetSizerCoord(fWhichSizer-1, kGetMaxCoord);
  1544.     theMin := Max(theMin, temp+minSizerPane);
  1545.  
  1546.     IF fSplitDir = kSplitVertically
  1547.         THEN temp := fSizerView.fSize.h
  1548.         ELSE temp := fSizerView.fSize.v;
  1549.  
  1550.     theMax := temp - ((fSizerView.GetNumberOfPanes-fWhichSizer) * minSizerPane);
  1551.     { don’t let sizer rect overlap following ones }
  1552.     temp := fSizerView.GetSizerCoord(fWhichSizer+1, kGetMinCoord);
  1553.     theMax := Min(theMax, temp-minSizerPane);
  1554.  
  1555.     IF fSplitDir = kSplitVertically THEN BEGIN
  1556.         IF nextPoint.h < theMin
  1557.             THEN nextPoint.h := theMin
  1558.             ELSE nextPoint.h := MIN(nextPoint.h, theMax);
  1559.         END
  1560.     ELSE BEGIN
  1561.         IF nextPoint.v < theMin
  1562.             THEN nextPoint.v := theMin
  1563.             ELSE nextPoint.v := MIN(nextPoint.v, theMax);
  1564.         END;
  1565.     END;                                                { TSizerCommand.TrackConstrain }
  1566.  
  1567. {$S ADoCommand}
  1568.  
  1569. PROCEDURE TSizerCommand.DoIt; OVERRIDE;
  1570.  
  1571.     VAR
  1572.         tempRect:            VRect;
  1573.  
  1574.     BEGIN
  1575.     tempRect := fSizerView.MakeSizerRect(fNewEdge);
  1576.     fSizerView.SetPane(fWhichSizer, tempRect);
  1577.     END;                                                { TSizerCommand.DoIt }
  1578.  
  1579. {$S ADoCommand}
  1580.  
  1581. PROCEDURE TSizerCommand.UndoIt; OVERRIDE;
  1582.  
  1583.     VAR
  1584.         tempRect:            VRect;
  1585.         
  1586.     BEGIN
  1587.     tempRect := fOldSizerRect;
  1588.     fSizerView.SetPane(fWhichSizer, tempRect);
  1589.     END;                                                { TSizerCommand.UndoIt }
  1590.  
  1591. {$S ADoCommand}
  1592.  
  1593. PROCEDURE TSizerCommand.RedoIt; OVERRIDE;
  1594.  
  1595.     BEGIN
  1596.     DoIt;
  1597.     END;                                                { TSizerCommand.RedoIt }
  1598.  
  1599. PROCEDURE TSizerCommand.SetPenForFeedback(aPoint: VPoint);
  1600. { Set the pen pattern and size for showing feedback when tracking at the given point }
  1601.  
  1602.     BEGIN
  1603.     PenPat(black);
  1604.     PenSize(1, 1);
  1605.     END;
  1606.  
  1607. {$S AFields}
  1608.  
  1609. PROCEDURE TSizerCommand.Fields(PROCEDURE DoToField(fieldName: Str255; fieldAddr: Ptr;
  1610.                                                    fieldType: INTEGER)); OVERRIDE;
  1611.  
  1612.     BEGIN
  1613.     DoToField('TSizerCommand', NIL, bClass);
  1614.     DoToField('fSizerView', @fSizerView, bObject);
  1615.     DoToField('fNewEdge', @fNewEdge, bLongint);
  1616.     DoToField('fOldSizerRect', @fOldSizerRect, bVRect);
  1617.     DoToField('fSplitDir', @fSplitDir, bByte);
  1618.     DoToField('fWhichSizer', @fWhichSizer, bInteger);
  1619.     INHERITED Fields(DoToField);
  1620.     END;
  1621.  
  1622.  
  1623. {---------------------- TSplitterCommand ----------------------}
  1624.  
  1625. {$S ASelCommand}
  1626.  
  1627. PROCEDURE TSplitterCommand.ISplitterCommand(itsSizerView: TSizerView);
  1628. { Track over the entire SizerView }
  1629.  
  1630.     BEGIN
  1631.     ISizerCommand(itsSizerView, 0, itsSizerView.GetSplitDirection);
  1632.     fCanUndo := FALSE;        { Sorry, folks! }
  1633.     END;
  1634.  
  1635. {$S ADoCommand}
  1636.  
  1637. PROCEDURE TSplitterCommand.TrackConstrain(anchorPoint, previousPoint: VPoint;
  1638.                                           VAR nextPoint: VPoint); OVERRIDE;
  1639.  
  1640.     BEGIN
  1641.     { do nothing: tracking will be constrained to fSizerView. }
  1642.     END;
  1643.  
  1644. PROCEDURE TSplitterCommand.DoIt; OVERRIDE;
  1645.  
  1646.     VAR
  1647.         tempRect:        VRect;
  1648.         itsSetbacks:    VRect;
  1649.         paneToSplit:    TView;
  1650.         newPane:        TView;
  1651.         splitter:        TSplitter;
  1652.         scroller:        TScroller;
  1653.         whichPane:        INTEGER;
  1654.         temp:            LONGINT;
  1655.  
  1656.     BEGIN
  1657.     { figure out which pane the tracker stopped in }
  1658.     tempRect := fSizerView.MakeSizerRect(fNewEdge);
  1659.     {$Push} {$H-}
  1660.     paneToSplit := fSizerView.FindPaneAt(tempRect.topLeft);
  1661.     {$Pop}
  1662.  
  1663.     IF paneToSplit <> NIL THEN BEGIN    { found a pane to split }
  1664.         whichPane := fSizerView.FindPane(paneToSplit);
  1665.         newPane := CloneAView(paneToSplit);
  1666.         IF (Member(newPane, TScroller)) & (whichPane = 1) THEN
  1667.             BEGIN    { remove scrollbar offset for splitter control from new pane }
  1668.             splitter := fSizerView.fSplitter;
  1669.             scroller := TScroller(newPane);
  1670.             temp := splitter.GetThickness;
  1671.             WITH scroller.fSBarOffsets DO
  1672.                 IF fSplitDir = h
  1673.                     THEN top := top - temp
  1674.                     ELSE left := left - temp;
  1675.             END;
  1676.         itsSetbacks := fSizerView.fSetbacks.At(whichPane); { just copy split pane's setbacks }
  1677.         fSizerView.AddPane(newPane, fNewEdge, itsSetbacks);
  1678.         fSizerView.ForceRedraw;
  1679.         END;
  1680.     END;
  1681.  
  1682. {$S ADoCommand}
  1683.  
  1684. PROCEDURE TSplitterCommand.SetPenForFeedback(aPoint: VPoint); OVERRIDE;
  1685.  
  1686.     BEGIN
  1687.     IF fSizerView.IsValidSplitPt(aPoint)
  1688.         THEN PenPat(black)
  1689.         ELSE PenPat(ltGray);
  1690.     PenSize(1, 1);
  1691.     END;
  1692.  
  1693. FUNCTION TSplitterCommand.TrackMouse(aTrackPhase: TrackPhase;
  1694.                                      VAR anchorPoint, previousPoint, nextPoint: VPoint;
  1695.                                      mouseDidMove: BOOLEAN): TCommand; OVERRIDE;
  1696. { Arguments are in fSizerView coordinates }
  1697.  
  1698.     BEGIN
  1699.     TrackMouse := SELF;                            { keep on trackin’ }
  1700.     IF fSplitDir = kSplitVertically
  1701.         THEN fNewEdge := nextPoint.h
  1702.         ELSE fNewEdge := nextPoint.v;
  1703.  
  1704.     IF aTrackPhase = trackRelease THEN
  1705.         IF NOT fSizerView.IsValidSplitPt(nextPoint) THEN    { can’t split here }
  1706.             TrackMouse := NIL;                    { …so just forget it }
  1707.     END;                                        { TSplitterCommand.TrackMouse }
  1708.  
  1709. {$S AFields}
  1710.  
  1711. PROCEDURE TSplitterCommand.Fields(PROCEDURE DoToField(fieldName: Str255; fieldAddr: Ptr;
  1712.                                             fieldType: INTEGER)); OVERRIDE;
  1713.  
  1714.     BEGIN
  1715.     DoToField('TSplitterCommand', NIL, bClass);
  1716.     INHERITED Fields(DoToField);
  1717.     END;
  1718.  
  1719. {-------------------------- TSplitter ----------------------}
  1720.  
  1721. {$S AOpen}
  1722.  
  1723. PROCEDURE TSplitter.IRes(itsDocument: TDocument; itsSuperView: TView;
  1724.                          VAR itsParams: Ptr); OVERRIDE;
  1725.  
  1726.     BEGIN
  1727.     IF qDebug & (NOT Member(itsSuperView, TSizerView)) THEN
  1728.         ProgramBreak('Splitter’s superview must be a TSizerView!');
  1729.     fSizerView := NIL;
  1730.  
  1731.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  1732.  
  1733.     IFinish(itsSuperView);
  1734.     END;
  1735.  
  1736. PROCEDURE TSplitter.ISplitter(itsDocument: TDocument; itsSuperview: TView;
  1737.                               itsLocation: VPoint; itsSize: VPoint);
  1738.  
  1739.     BEGIN
  1740.     IF qDebug & (NOT Member(itsSuperView, TSizerView)) THEN
  1741.         ProgramBreak('Splitter’s superview must be a TSizerView!');
  1742.  
  1743.     fSizerView := NIL;
  1744.     IControl(itsSuperView, itsLocation, itsSize, sizeRelSuperView, sizeRelSuperView);
  1745.  
  1746.     IFinish(itsSuperView);
  1747.     ViewEnable(TRUE, kDontRedraw);
  1748.     END;
  1749.  
  1750. PROCEDURE TSplitter.IFinish(itsSuperView: TView);
  1751. { Finish up initialization by setting the fSizerView and fLocDeterminer fields }
  1752.  
  1753.     BEGIN
  1754.     fSizerView := TSizerView(itsSuperView);
  1755.     IF fSizerView.GetSplitDirection = v THEN BEGIN
  1756.         fLocDeterminer[v] := kLocationVaries;
  1757.         fLocDeterminer[h] := kLocationFixed;
  1758.         END
  1759.     ELSE BEGIN    { h }
  1760.         fLocDeterminer[h] := kLocationVaries;
  1761.         fLocDeterminer[v] := kLocationFixed;
  1762.         END;
  1763.     fSizerView.fSplitter := SELF;
  1764.     END;
  1765.  
  1766. {$S ASelCommand}
  1767.  
  1768. FUNCTION TSplitter.DoMouseCommand(VAR theMouse: Point; VAR info: EventInfo;
  1769.                                   VAR hysteresis: Point): TCommand; OVERRIDE;
  1770. { Override to return a TSplitterCommand. theMouse is in local view coordinates }
  1771.  
  1772.     VAR
  1773.         aSplitterCommand:    TSplitterCommand;
  1774.  
  1775.     BEGIN
  1776.     IF fSizerView <> NIL THEN BEGIN
  1777.         NEW(aSplitterCommand);
  1778.         FailNIL(aSplitterCommand);
  1779.         aSplitterCommand.ISplitterCommand(fSizerView);
  1780.         DoMouseCommand := aSplitterCommand;
  1781.         END
  1782.     ELSE
  1783.         DoMouseCommand := INHERITED DoMouseCommand(theMouse, info, hysteresis);
  1784.     END;
  1785.  
  1786. {$S ARes}
  1787. PROCEDURE TSplitter.Draw(area: Rect); OVERRIDE;
  1788. { Default is just a black rectangle, like a splitter well }
  1789.  
  1790.     BEGIN
  1791.     ControlArea(area);
  1792.     PenPat(black);
  1793.     PenMode(patCopy);
  1794.     PaintRect(area);
  1795.  
  1796.     INHERITED Draw(area);
  1797.     END;
  1798.  
  1799. {$S ADoCommand}
  1800. FUNCTION TSplitter.GetThickness: LONGINT;
  1801.  
  1802.     BEGIN
  1803.     {$IFC qDebug}
  1804.     IF fSizerView = NIL THEN ProgramBreak('Splitter has no fSizerView!')
  1805.     ELSE
  1806.     {$ENDC}
  1807.  
  1808.     IF fSizerView.GetSplitDirection = h
  1809.         THEN GetThickness := fSize.v
  1810.         ELSE GetThickness := fSize.h;
  1811.     END;
  1812.  
  1813. {$S ANonRes}
  1814.  
  1815. PROCEDURE TSplitter.SuperViewChangedSize(delta: VPoint; invalidate: BOOLEAN); OVERRIDE;
  1816.  
  1817.     VAR
  1818.         loc:    VPoint;
  1819.  
  1820.     BEGIN
  1821.     IF fLocDeterminer[h] | fLocDeterminer[v] THEN BEGIN
  1822.         loc := fLocation;
  1823.         IF fLocDeterminer[h] THEN
  1824.             loc.h := loc.h + delta.h;        { compute its new horizontal position }
  1825.         IF fLocDeterminer[v] THEN
  1826.             loc.v := loc.v + delta.v;        { compute its new vertical position }
  1827.         Locate(loc.h, loc.v, invalidate);    { move it }
  1828.         END;
  1829.     END;
  1830.  
  1831. {$S AFields}
  1832.  
  1833. PROCEDURE TSplitter.Fields(PROCEDURE DoToField(fieldName: Str255; fieldAddr: Ptr;
  1834.                                                fieldType: INTEGER)); OVERRIDE;
  1835.     CONST
  1836.         kFixedString = 'Fixed';
  1837.         kVariesString = 'Varies';
  1838.  
  1839.     VAR
  1840.         str:    Str255;
  1841.  
  1842.     BEGIN
  1843.     DoToField('TSplitter', NIL, bClass);
  1844.     DoToField('fSizerView', @fSizerView, bObject);
  1845.     IF fLocDeterminer[h]
  1846.         THEN str := kVariesString
  1847.         ELSE str := kFixedString;
  1848.     DoToField('fLocDeterminer[h]', @str, bString);
  1849.     IF fLocDeterminer[v]
  1850.         THEN str := kVariesString
  1851.         ELSE str := kFixedString;
  1852.     DoToField('fLocDeterminer[v]', @str, bString);
  1853.     INHERITED Fields(DoToField);
  1854.     END;
  1855.  
  1856. {---------------------- TDeSizerCommand ----------------------}
  1857.  
  1858. {$S ASelCommand}
  1859.  
  1860. PROCEDURE TDeSizerCommand.IDeSizerCommand(itsSizerView: TSizerView; whichSizer: INTEGER;
  1861.                                           whichWay: VHSelect);
  1862. { Track over the entire SizerView, but show gray when too close to neighboring panes,
  1863.   and show white when close to the SizerView ends. }
  1864.  
  1865.     VAR
  1866.         vr1, vr2:        VRect;
  1867.         minPaneSize:    VCoordinate;
  1868.  
  1869.     BEGIN
  1870.     ISizerCommand(itsSizerView, whichSizer, whichWay);
  1871.     fCanUndo := FALSE;                    { Sorry, folks! }
  1872.  
  1873.     fResizeOK := TRUE;
  1874.     { build the rectangle in which a valid resize can occur }
  1875.     vr1 := itsSizerView.GetSizerRect(whichSizer-1);
  1876.     vr2 := itsSizerView.GetSizerRect(whichSizer+1);
  1877.     minPaneSize := itsSizerView.GetMinPaneLength;
  1878.     IF whichWay = h THEN BEGIN
  1879.         fResizeRect.top := vr1.bottom + minPaneSize;
  1880.         fResizeRect.left := vr1.left;
  1881.         fResizeRect.bottom := vr2.top - minPaneSize;
  1882.         fResizeRect.right := vr2.right;
  1883.         END
  1884.     ELSE BEGIN { v }
  1885.         fResizeRect.left := vr1.right + minPaneSize;
  1886.         fResizeRect.top := vr1.top;
  1887.         fResizeRect.right := vr2.left - minPaneSize;
  1888.         fResizeRect.bottom := vr2.bottom;
  1889.         END;
  1890.     END;
  1891.  
  1892. {$S ADoCommand}
  1893.  
  1894. PROCEDURE TDeSizerCommand.TrackConstrain(anchorPoint, previousPoint: VPoint;
  1895.                                        VAR nextPoint: VPoint); OVERRIDE;
  1896.  
  1897.     BEGIN
  1898.     { Don’t change nextPoint, so tracking is constrained to fSizerView }
  1899.  
  1900.     { Determine whether nextPoint is a valid place to which to move the sizer bars }
  1901.     {$Push} {$H-}
  1902.     fResizeOK := PtInVRect(nextPoint, fResizeRect);    {$Pop}
  1903.     END;
  1904.  
  1905. PROCEDURE TDeSizerCommand.SetPenForFeedback(aPoint: VPoint); OVERRIDE;
  1906.  
  1907.     BEGIN
  1908.     {$Push} {$H-}
  1909.     IF PtInVRect(aPoint, fResizeRect) THEN    {$Pop}
  1910.         PenPat(black)
  1911.     ELSE IF fSizerView.IsValidSplitPt(aPoint) THEN
  1912.         PenPat(ltGray)
  1913.     ELSE
  1914.         PenPat(white);
  1915.     PenSize(1, 1);
  1916.     END;
  1917.  
  1918. PROCEDURE TDeSizerCommand.DoIt; OVERRIDE;
  1919. { If final mouse position was at either end of the SizerView, delete the sizer bars. }
  1920.  
  1921.     VAR
  1922.         tempRect:            VRect;
  1923.         paneToDelete:        INTEGER;
  1924.  
  1925.     FUNCTION IsVpt1LessThan2(vpt1, vpt2: VPoint): BOOLEAN;
  1926.  
  1927.         BEGIN
  1928.         IF fSplitDir = h
  1929.             THEN IsVpt1LessThan2 := (vpt1.v < vpt2.v)
  1930.             ELSE IsVpt1LessThan2 := (vpt1.h < vpt2.h);
  1931.         END;
  1932.  
  1933.     BEGIN
  1934.     tempRect := fSizerView.MakeSizerRect(fNewEdge);
  1935.     IF NOT fSizerView.IsValidSplitPt(tempRect.topLeft) THEN    { sizer dragged to end }
  1936.         BEGIN                                    { delete sizer rect and pane }
  1937.         {$Push} {$H-}
  1938.         IF IsVpt1LessThan2(tempRect.topLeft, fOldSizerRect.topLeft)    {$Pop}
  1939.             THEN paneToDelete := fWhichSizer        { delete pane before sizer }
  1940.             ELSE paneToDelete := fWhichSizer + 1;    { delete pane after sizer }
  1941.         IF fSizerView.DeletePane(paneToDelete, fWhichSizer) = NIL THEN ;
  1942.         END
  1943.     ELSE                                        { just move sizer rect }
  1944.         fSizerView.SetPane(fWhichSizer, tempRect);
  1945.     END;                                        { TDeSizerCommand.DoIt }
  1946.  
  1947. FUNCTION TDeSizerCommand.TrackMouse(aTrackPhase: TrackPhase; VAR anchorPoint, previousPoint,
  1948.                                     nextPoint: VPoint; mouseDidMove: BOOLEAN): TCommand; OVERRIDE;
  1949. { Arguments are in fSizerView coordinates }
  1950.  
  1951.     VAR
  1952.         cmd:             TCommand;
  1953.  
  1954.     BEGIN
  1955.     cmd := INHERITED TrackMouse(aTrackPhase, anchorPoint, previousPoint, nextPoint, mouseDidMove);
  1956.     IF aTrackPhase = trackRelease THEN
  1957.         IF (NOT fResizeOK) &                        { not a valid resizing area }
  1958.            (fSizerView.IsValidSplitPt(nextPoint))    { not a sizer deletion area }
  1959.             THEN cmd := NIL;
  1960.     TrackMouse := cmd;
  1961.     END;                                        { TDeSizerCommand.TrackMouse }
  1962.  
  1963. {$S AFields}
  1964.  
  1965. PROCEDURE TDeSizerCommand.Fields(PROCEDURE DoToField(fieldName: Str255; fieldAddr: Ptr;
  1966.                                         fieldType: INTEGER)); OVERRIDE;
  1967.  
  1968.     BEGIN
  1969.     DoToField('TDeSizerCommand', NIL, bClass);
  1970.     DoToField('fResizeRect', @fResizeRect, bVRect);
  1971.     DoToField('fResizeOK', @fResizeOK, bBoolean);
  1972.     INHERITED Fields(DoToField);
  1973.     END;
  1974.  
  1975.